/*
 * Copyright (c) 2020, yifengling0. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. No personal names or organizations' names associated with the
 *    Atomthreads project may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#include "atom.h"
#include "hw.h"
#include "drv_common.h"
#include "console.h"
#include "stm8l15x.h"
#include "stm8l15x_clk.h"
#include "stm8l15x_wwdg.h"
#include "debug.h"

#ifdef COM_USE_CONSOLE

static enConsoleResult reboot(int argc, char **argv)
{
    WWDG_SWReset();
    
    return CE_OK;
}

//   CLK_SYSCLKSource_HSI = (uint8_t)0x01, /*!< System Clock Source HSI */
//   CLK_SYSCLKSource_LSI = (uint8_t)0x02, /*!< System Clock Source LSI */
//   CLK_SYSCLKSource_HSE = (uint8_t)0x04, /*!< System Clock Source HSE */
//   CLK_SYSCLKSource_LSE = (uint8_t)0x08  /*!< System Clock Source LSE */

static const char *clk_source_str[] = {
    "HSI",
    "LSI",
    "HSE",
    "LSE"
};

static enConsoleResult clock(int argc, char **argv)
{
    uint32_t freq;
    CLK_SYSCLKSource_TypeDef source;

    freq = CLK_GetClockFreq();
    source = CLK_GetSYSCLKSource();

    DBG_COLOR_GREEN();
    KPrintf("Clock frequency: %d Hz\r\n", freq);
    KPrintf("Clock source: %s\r\n", clk_source_str[(int)source]);
    DBG_COLOR_END();
        
    return CE_OK;
}



#endif

BGEIN_DEF_CMD(_commCommands)
    CMD_DEF(reboot, "reboot the system")
    CMD_DEF(clock, "get system clock")
END_DEF_CMD()

//所有gpio默认初始化为output 低降低功耗
static void gpio_init_out_low(void)
{
    GPIO_Init(GPIOA, GPIO_Pin_All, GPIO_Mode_Out_OD_Low_Slow);
    GPIO_Init(GPIOB, GPIO_Pin_All, GPIO_Mode_Out_OD_Low_Slow);
    GPIO_Init(GPIOC, GPIO_Pin_All, GPIO_Mode_Out_OD_Low_Slow);
    GPIO_Init(GPIOD, GPIO_Pin_All, GPIO_Mode_Out_OD_Low_Slow);
    GPIO_Init(GPIOE, GPIO_Pin_All, GPIO_Mode_Out_OD_Low_Slow);
    GPIO_Init(GPIOF, GPIO_Pin_All, GPIO_Mode_Out_OD_Low_Slow);
    GPIO_Init(GPIOG, GPIO_Pin_All, GPIO_Mode_Out_OD_Low_Slow);
    
    GPIO_WriteBit(GPIOA, GPIO_Pin_All, RESET);
    GPIO_WriteBit(GPIOB, GPIO_Pin_All, RESET);
    GPIO_WriteBit(GPIOC, GPIO_Pin_All, RESET);
    GPIO_WriteBit(GPIOD, GPIO_Pin_All, RESET);
    GPIO_WriteBit(GPIOE, GPIO_Pin_All, RESET);
    GPIO_WriteBit(GPIOF, GPIO_Pin_All, RESET);
    GPIO_WriteBit(GPIOG, GPIO_Pin_All, RESET);
}

void DrvCommonInit(void)
{
    gpio_init_out_low();
    CONSOLE_REG_CMD(_commCommands);
}

void HwDelayMs(uint32_t ms)
{
    uint32_t freq = CLK_GetClockFreq();

    /* Init TIMER 2 */
    CLK_PeripheralClockConfig(CLK_Peripheral_TIM2, ENABLE);

    /* prescaler: / (2^0) = /1 */
    TIM2->PSCR = 0;

    /* SYS_CLK_HSI_DIV1 Auto-Reload value: 16M / 1 = 16M, 16M / 100k = 160 */
    uint16_t count = (uint16_t)(freq/100000);

    TIM2->ARRH = ((count >> 8) & 0xff);
    TIM2->ARRL = (count & 0xff);

    /* Counter value: 1000, to compensate the initialization of TIMER */
    TIM2->CNTRH = 0x03;
    TIM2->CNTRL = 0xe8;

    /* clear update flag */
    TIM2->SR1 &= ~TIM_SR1_UIF;

    /* Enable Counter */
    TIM2->CR1 |= TIM_CR1_CEN;

    while(ms--)
    {
        while((TIM2->SR1 & TIM_SR1_UIF) == 0) ;
        TIM2->SR1 &= ~TIM_SR1_UIF;
    }

    /* Disable Counter */
    TIM2->CR1 &= ~TIM_CR1_CEN;
    CLK_PeripheralClockConfig(CLK_Peripheral_TIM2, DISABLE);
}

void HwDelayUs(uint32_t us)
{
    /* Init TIMER 4 */
    for(int i = 0; i < us; i++){
       nop();
    }
}